/*
 * Copyright 2021-2022 Open Kunlun Technology <https://www.openkunlun.io>
 */

package io.openkunlun.scaladsl.server

import akka.actor.{ ExtendedActorSystem, Extension, ExtensionId, ExtensionIdProvider }
import akka.grpc.scaladsl.Metadata
import io.openkunlun.scaladsl.v1.{ InvokeRequest, InvokeResponse }

import scala.concurrent.{ ExecutionContext, Future }

/**
 * @author ericxin.
 */
private[server] object DaprInvocation extends ExtensionId[DaprInvocation] with ExtensionIdProvider {
  override def lookup: ExtensionId[DaprInvocation] = DaprInvocation
  override def createExtension(system: ExtendedActorSystem) = new DaprInvocation(system)
}
private[server] class DaprInvocation(system: ExtendedActorSystem) extends Extension {

  private val lock = new Object()
  @volatile private var handlers = Map.empty[String, InvocationHandler]

  /**
   *
   * @param handler
   */
  def addHandler(handler: InvocationHandler): Unit = {
    lock.synchronized {
      handler.methods.foreach(method => handlers = handlers + (method -> handler))
    }
  }

  /**
   *
   * @param method
   * @return
   */
  def getHandler(method: String): Option[InvocationHandler] = {
    handlers.get(method)
  }

  /**
   *
   * @param in
   * @param metadata
   * @param ec
   * @return
   */
  def onInvoke(in: InvokeRequest, metadata: Metadata)(implicit ec: ExecutionContext): Future[InvokeResponse] = {
    handlers
      .get(in.method)
      .map(it => it.handle(in, metadata)(ec))
      .getOrElse(Future.failed(new InvocationHandlerNotFoundException(in.method)))
  }

  def isHealthy: Boolean = handlers.nonEmpty
}